package ryarithsGame;

import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jme.scene.SharedMesh;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Cylinder;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;

public class Fence extends Node
{
	
	private static final long serialVersionUID = 1L;
	private Texture t;
	private float fenceX, fenceZ, fenceLength;
	
	public Fence(String name, float x, float z, float length)
	{
		super(name);
		buildFence(x,z,length);
		fenceX = x;
		fenceZ = z;
		fenceLength = length;
	}
	
	private void buildFence(float x, float z, float length) 
	{
						
        //This cylinder will act as the four main posts at each corner
        Cylinder postGeometry = new Cylinder("post", 10, 10, 1, 30);
        Quaternion q = new Quaternion();
        //rotate the cylinder to be vertical
        q.fromAngleAxis(FastMath.PI/2, new Vector3f(1,0,0));
        postGeometry.setLocalRotation(q);
        postGeometry.setModelBound(new BoundingBox());
        postGeometry.updateModelBound();
        
        //We will share the post 4 times (one for each post)
        //It is *not* a good idea to add the original geometry 
        //as the sharedmeshes will alter its local values.
        //We then translate the posts into position. 
        //Magic numbers are bad, but help illustrate the point.:)
        SharedMesh post1 = new SharedMesh("post1", postGeometry);
        post1.setLocalTranslation(new Vector3f((x-length/2),15f,(z-length/2)));
        SharedMesh post2 = new SharedMesh("post2", postGeometry);
        post2.setLocalTranslation(new Vector3f((x+length/2),15f,(z-length/2)));
        SharedMesh post3 = new SharedMesh("post3", postGeometry);
        post3.setLocalTranslation(new Vector3f((x-length/2),15f,(z+length/2)));
        SharedMesh post4 = new SharedMesh("post4", postGeometry);
        post4.setLocalTranslation(new Vector3f((x+length/2),15f,(z+length/2)));
        
        //This cylinder will be the horizontal struts that hold
        //the field in place.
        Cylinder strutGeometry = new Cylinder("strut", 10,10, 0.125f, length);
        strutGeometry.setModelBound(new BoundingBox());
        strutGeometry.updateModelBound();
        
        //again, we'll share this mesh.
        //Some we need to rotate to connect various posts.
        SharedMesh strut1 = new SharedMesh("strut1", strutGeometry);
        Quaternion rotate90 = new Quaternion();
        rotate90.fromAngleAxis(FastMath.PI/2, new Vector3f(0,1,0));
        strut1.setLocalRotation(rotate90);
        strut1.setLocalTranslation(new Vector3f(x,30f,(z-length/2)));
        SharedMesh strut2 = new SharedMesh("strut2", strutGeometry);
        strut2.setLocalTranslation(new Vector3f((x-length/2),30f,z));
        SharedMesh strut3 = new SharedMesh("strut3", strutGeometry);
        strut3.setLocalTranslation(new Vector3f((x+length/2),30f,z));
        SharedMesh strut4 = new SharedMesh("strut4", strutGeometry);
        strut4.setLocalRotation(rotate90);
        strut4.setLocalTranslation(new Vector3f(x,30f,(z+length/2)));
        
        //Create the actual forcefield 
        //The first box handles the X-axis, the second handles the z-axis.
        //We don't rotate the box as a demonstration on how boxes can be 
        //created differently.
        Box forceFieldX = new Box("forceFieldX", new Vector3f(-length/2, -15f, -0.1f), new Vector3f(length/2, 15f, 0.1f));
        forceFieldX.setModelBound(new BoundingBox());
        forceFieldX.updateModelBound();
        //We are going to share these boxes as well
        SharedMesh forceFieldX1 = new SharedMesh("forceFieldX1",forceFieldX);
        forceFieldX1.setLocalTranslation(new Vector3f(x,15,(z-length/2)));
        SharedMesh forceFieldX2 = new SharedMesh("forceFieldX2",forceFieldX);
        forceFieldX2.setLocalTranslation(new Vector3f(x,15,(z+length/2)));
        
        //The other box for the Z axis
        Box forceFieldZ = new Box("forceFieldZ", new Vector3f(-0.1f, -15f, -length/2), new Vector3f(0.1f, 15f, length/2));
        forceFieldZ.setModelBound(new BoundingBox());
        forceFieldZ.updateModelBound();
        //and again we will share it
        SharedMesh forceFieldZ1 = new SharedMesh("forceFieldZ1",forceFieldZ);
        forceFieldZ1.setLocalTranslation(new Vector3f((x-length/2),15,z));
        SharedMesh forceFieldZ2 = new SharedMesh("forceFieldZ2",forceFieldZ);
        forceFieldZ2.setLocalTranslation(new Vector3f((x+length/2),15,z));
        
        //add all the force fields to a single node and make this node part of
        //the transparent queue.
        Node forceFieldNode = new Node("forceFieldNode");
        forceFieldNode.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
        forceFieldNode.attachChild(forceFieldX1);
        forceFieldNode.attachChild(forceFieldX2);
        forceFieldNode.attachChild(forceFieldZ1);
        forceFieldNode.attachChild(forceFieldZ2);
        
        //Add the alpha values for the transparent node
        BlendState as1 = DisplaySystem.getDisplaySystem().getRenderer().createBlendState();
        as1.setBlendEnabled(true);
        as1.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
        as1.setDestinationFunction(BlendState.DestinationFunction.One);
        as1.setTestEnabled(true);
        as1.setTestFunction(BlendState.TestFunction.GreaterThan);
        as1.setEnabled(true);
        
        forceFieldNode.setRenderState(as1);
        
        //load a texture for the force field elements
        TextureState ts = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
        t = TextureManager.loadTexture(Fence.class.getClassLoader()
                  .getResource("data/textures/reflector.jpg"),
                  Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear);
        t.setWrap(Texture.WrapMode.Repeat);
        t.setTranslation(new Vector3f());
        ts.setTexture(t);
        
        forceFieldNode.setRenderState(ts);
        
       
        //put all the posts into a tower node
        Node towerNode = new Node("tower");
        towerNode.attachChild(post1);
        towerNode.attachChild(post2);
        towerNode.attachChild(post3);
        towerNode.attachChild(post4);
        
        //add the tower to the opaque queue (we don't want to be able to see through them)
        //and we do want to see them through the forcefield.
        towerNode.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
        
        //load a texture for the towers
        TextureState ts2 = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
        Texture t2 = TextureManager.loadTexture(Fence.class.getClassLoader()
                  .getResource("data/textures/post.jpg"),
                  Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear);
        
        ts2.setTexture(t2);
        
        towerNode.setRenderState(ts2);
        
        //put all the struts into a single node.
        Node strutNode = new Node("strutNode");
        strutNode.attachChild(strut1);
        strutNode.attachChild(strut2);
        strutNode.attachChild(strut3);
        strutNode.attachChild(strut4);
        //this too is in the opaque queue.
        strutNode.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
        
        //load a texture for the struts
        TextureState ts3 = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
        Texture t3 = TextureManager.loadTexture(Fence.class.getClassLoader()
                  .getResource("data/textures/rust.jpg"),
                  Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear);
        
        ts3.setTexture(t3);
        
        strutNode.setRenderState(ts3);
        
        //Attach all the pieces to the main fence node
        this.attachChild(forceFieldNode);
        this.attachChild(towerNode);
        this.attachChild(strutNode);
    }

	public void updateFence(float tpf)
    {
    	t.getTranslation().y += 0.3f * tpf;//timer.getTimePerFrame();
		if(t.getTranslation().y > 1) 
		{
            t.getTranslation().y = 0;
		}
    }

	public boolean checkCollision(Vector3f pos)
	{
		float x0,z0,xX,zZ;
		
		x0 = fenceX - fenceLength/2;
		z0 = fenceZ - fenceLength/2;
		xX = fenceX + fenceLength/2;
		zZ = fenceZ + fenceLength/2;
		
		if(FastMath.abs(pos.x-x0) <= 2 || FastMath.abs(pos.x-xX) <= 2 || FastMath.abs(pos.z-z0) <= 2 || FastMath.abs(pos.z-zZ) <= 2)
			return true;
		return false;
	}
}
